#include <unistd.h>
#include <cstring>
#include <fstream>
#include <iostream>
#include "aiui/AIUI_V2.h"
#include "aiui/PcmPlayer_C.h"
#include "json/json.h"
#include "StreamNlpTtsHelper.h"
#include "IatResultUtil.h"
#include "Base64Util.h"
#include <sys/socket.h>
#include <net/if.h>
#include <sys/ioctl.h>

#define AIUI_SLEEP(x) usleep(x * 1000)
// 使用的AIUI服务版本：1（语义技能），2（语义技能 + 大模型），3（语义技能 + 大模型 + 极速交互）
#define AIUI_VER 3

#if AIUI_VER == 3
    // 是否使用语义后合成。当在AIUI平台应用配置页面打开"语音合成"开关时，需要打开该宏
    #define USE_POST_SEMANTIC_TTS 1
#endif
using namespace std;
using namespace aiui_va;
using namespace aiui_v2;



/**
 * 测试语音合成，返回pcm数据。
 *
 * @param text
 */
void startTTS(const string& text, const string& tag = "");

// 从IAIUIListener派生自己的结果监听器
class REIListener : public IAIUIListener
{
private:
    // 从StreamNlpTtsHelper::Listener派生流式合成监听器，用于监听大模型结果的合成
    class TtsHelperListener : public StreamNlpTtsHelper::Listener{
    public:
        void onText(const StreamNlpTtsHelper::OutTextSeg& textSeg) override {
            if (textSeg.isBegin() || textSeg.isEnd()) {
                if (aiui_pcm_player_get_state() != PCM_PLAYER_STATE_STARTED) {
                    aiui_pcm_player_start();
                }
                if (textSeg.isBegin()) {
                    aiui_pcm_player_clear();
                }
            }

            // 调用合成
            startTTS(textSeg.mText, textSeg.mTag);
        }

        void onFinish(const string& fullText) override {
            // 文本合成完成回调
            cout << "tts, fullText=" << fullText << endl;
        }

        void onTtsData(const Json::Value& bizParamJson, const char* audio, int len) override {
            const Json::Value& data = (bizParamJson["data"])[0];
            const Json::Value& content = (data["content"])[0];
            int dts = content["dts"].asInt();
            int progress = content["text_percent"].asInt();

            // 将合成数据写入播放器
            aiui_pcm_player_write(0, audio, len, dts, progress);
        }
    };
    
    /**
     * 重写onEvent方法，SDK通过回调该方法抛出各种事件，在这里针对事件做对应的处理。
     *
     * @param event
     */
    void onEvent(const IAIUIEvent& event) override;
    // 是否输出更多信息
    
private:
    std::shared_ptr<StreamNlpTtsHelper> m_pTtsHelper;
    int mStreamTtsIndex{0};
    
public:

    REIListener();
    ~REIListener()
    {
        // 析构时销毁播放器，释放资源
        aiui_pcm_player_destroy();
    }
    fstream mFs;

    string mCurTtsSid;// 当前合成sid
    string mCurIatSid;// 当前识别sid
    string mIatTextBuffer;// 识别结果缓存
    string mStreamNlpAnswerBuffer;// 流式nlp的应答语缓存
    int mTtsLen = 0;// 当前收到了tts音频的长度
    int mIntentCnt = 0;// 意图的数量
    bool mMoreDetails = true;
    static void processIntentJson(Json::Value& params,
                           Json::Value& intentJson,
                           std::string& resultStr,
                           int eosRsltTime,
                           std::string& sid);

    void handleEvent(const IAIUIEvent& event);
    // // 是否输出更多信息
    // 
};



#define TEST_ROOT_DIR "./REIAIUI/"
#define CFG_FILE_PATH "./REIAIUI/cfg/aiui.cfg"
#define TEST_AUDIO_PATH "./REIAIUI/audio/test.pcm"
#define LOG_DIR         "./REIAIUI/log/"
#define MSC_DIR         "./REIAIUI/msc/"
#define TEST_TTS_PATH   "./REIAIUI/text/tts.txt"
#define TEST_SEE_SAY_PATH "./REIAIUI/text/see_say.txt"
#define VOICE_CLONE_AUDIO_PATH "./REIAIUI/audio/voice_clone_1ch24K16bit.pcm"
#define VOICE_CLONE_RES_ID_PATH "./voice_clone_reg_id.txt"
#define WAKE_WORD_TEXT_PATH "./REIAIUI/text/wakeup_wake.txt"


/**
 * 读取文件内容存到字符串。
 *
 * @param path
 * @return
 */
string readFileAsString(const string& path);

#define SEND_AIUIMESSAGE(cmd, arg1, arg2, params, data)                               \
    do {                                                                         \
        if (!g_pAgent) break;                                                       \
        IAIUIMessage* msg = IAIUIMessage::create(cmd, arg1, arg2, params, data); \
        g_pAgent->sendMessage(msg);                                                 \
        msg->destroy();                                                          \
    } while (false)
//简化向g_pAgent发送消息的操作。
#define SEND_AIUIMESSAGE4(cmd, arg1, arg2, params) SEND_AIUIMESSAGE(cmd, arg1, arg2, params, nullptr)
#define SEND_AIUIMESSAGE3(cmd, arg1, arg2)              SEND_AIUIMESSAGE4(cmd, arg1, arg2, "")
#define SEND_AIUIMESSAGE2(cmd, arg1)                         SEND_AIUIMESSAGE3(cmd, arg1, 0)
#define SEND_AIUIMESSAGE1(cmd)                                    SEND_AIUIMESSAGE2(cmd, 0)

/**
 * 创建AIUIAgent对象。
 *
 * @param more
 * @param cfgPath
 */
void createAgent(bool more = true, const char* cfgPath = CFG_FILE_PATH);

/**
 * 销毁AIUIAgent对象。
 */
void destroyAgent();

/**
 * 唤醒AIUI。
 */
void wakeup();

/**
 * 重置唤醒，即回到待唤醒状态。
 */
void resetWakeup();

/**
 * 停止AIUI服务。
 */
void stop();

/**
 * 开启AIUI服务，此接口是与stop()对应，调用stop()之后必须调用此接口才能继续与SDK交互。
 *
 * 注：AIUIAgent创建成功之后AIUI会自动开启，故若非调用过stop()则不需要调用start()。
 */
void start();

/**
 * 重置AIUI服务，相当于先调用stop()再调用start()。一般用不到。
 */
void resetAIUI();

/**
 * 从文件读音频写入SDK，即用文件数据模型实时录音数据。
 *
 * @param repeat
 */
void writeAudioFromLocal(bool repeat);

/**
 * 开启录音。
 */
void startRecordAudio();

/**
 * 停止录音。
 */
void stopRecordAudio();

/**
 * 写入文本进行交互。
 *
 * @param text 文本内容
 * @param needWakeup 是否需要唤醒
 */
void writeText(const string& text, bool needWakeup = true);

/**
 * 测试语音合成，返回pcm数据。
 *
 * @param text
 */
void startTTS(const string& text, const string& tag);

/**
 * 测试流式语音合成，即分段上传文本，返回pcm数据。
 *
 * @param text 待合成文本
 * @param dts 数据流状态，取值：0（第一块数据），1（中间数据），2（最后一块数据）
 */
void startTTS(const string& text, int dts, const string& tag);

/**
 * 测试超拟人语音合成，返回pcm数据。
 *
 * @param text
 */
void startHTS(const string& text, const string& tag);

/**
 * 测试语音合成，返回url。
 *
 * @param text
 */
void startTTSUrl(const string& text);

/**
 * 构建esr语法。
 *
 * 注：新版本SDK都只支持esr。
 */
void buildEsrGrammar();

/**
 * 将麦克风参数切换到单麦设置。
 */
void changeMicTypeToMic1();

/**
 * 清除语义对话历史。
 */
void cleanDialogHistory();

/**
 * 同步动态实体。
 */
void syncSchemaData(int type = AIUIConstant::SYNC_DATA_SCHEMA);

/**
 * 同步所见即可说的内容。
 */
void syncV2SeeSayData();

/**
 * 上传需要复刻的音频资源
 * 音频格式:　
 *    采样率: 24000　
 *    通道数: 1　
 *    位深: 16　
 *    编码格式: 裸音频pcm
 */
void voiceCloneReg(string resPath = VOICE_CLONE_AUDIO_PATH);

/**
 * 删除声音复刻的资源
 */
void voiceCloneDelRes();

/**
 * 测试声音复刻的tts
 *
 * @param text
 */
void startVoiceCloneTTS(const string& text, const string& tag);

/**
 * 查询声音复刻注册的资源信息
 */
void voiceCloneQueryRes();

/**
 * AIUI登录操作，只有AIUI_V2才支持。
 */
void aiuiLogin();

/**
 * 获取mac地址。
 *
 * @param mac
 */
static void GenerateMACAddress(char* mac);

/**
 * 初始化设置。
 *
 * @param log
 */
static void initSetting(bool log = true);